﻿using System.Collections.ObjectModel;
using System.Globalization;
using System.Text.RegularExpressions;

namespace Central.Linq {

	/// <summary>
	/// Класс предиката фильтра
	/// </summary>
	public class FilterPredicate {
		#region конструктор

		/// <summary>
		/// Конструктор
		/// </summary>
		public FilterPredicate() {
			this.Values = new Collection<object>();
		}

		/// <summary>
		/// Конструктор
		/// </summary>
		public FilterPredicate(string where, Collection<object> values)
			: this() {
			if (!string.IsNullOrEmpty(where) && values != null)
				// замена в строке фильтра индексов значений в соответствие с коллекцией values
				this.Where = Regex.Replace(where, @"@\d+", delegate(Match match) {
					// индекс значения
					int indexValueResult;

					if (int.TryParse(match.Value.Substring(1), out indexValueResult)) {
						if (values.Count <= indexValueResult)
							indexValueResult = values.Count - 1;
						object value = values[indexValueResult];
						if (value != null) {
							indexValueResult = this.Add(value);
						}
						return string.Concat("@", (indexValueResult).ToString(CultureInfo.CurrentCulture));
					}
					else
						return match.Value;
				});
		}

		#endregion конструктор

		/// <summary>
		/// Строка фильтра
		/// </summary>
		public string Where { get; set; }

		/// <summary>
		/// Коллекция значений фильтра
		/// </summary>
		public Collection<object> Values { get; private set; }

		#region [+] cвойства

		/// <summary>
		/// Количество заданных значений в фильтре
		/// </summary>
		public int Count {
			get {
				return this.Values == null ? 0 : this.Values.Count;
			}
		}

		#endregion [+] cвойства

		#region методы

		/// <summary>
		/// Сравнение объектов
		/// </summary>
		/// <param name="obj"></param>
		/// <returns></returns>
		public override bool Equals(object obj) {
			return Equals(obj as FilterPredicate);
		}

		/// <summary>
		/// Сравнение объектов FilterPredicate
		/// </summary>
		/// <param name="other"></param>
		/// <returns></returns>
		public bool Equals(FilterPredicate other) {
			if (other == null)
				return false;

			return (other.Where.Equals(this.Where) && other.Values.Equals(this.Values));
		}

		/// <summary>
		/// Получение Hash кода объекта
		/// </summary>
		/// <returns></returns>
		public override int GetHashCode() {
			//Calculate the hash code
			return this.Where.GetHashCode() ^ this.Values.GetHashCode();
		}

		/// <summary>
		/// Метод добавления value в коллекцию значений
		/// </summary>
		/// <param name="filterValue"></param>
		public int Add(object filterValue) {
			if (filterValue == null)
				return -1;

			if (this.Values == null)
				this.Values = new Collection<object>();

			if (!this.Values.Contains(filterValue))
				this.Values.Add(filterValue);
			return this.Values.IndexOf(filterValue);
		}

		/// <summary>
		/// Метод удаления value из коллекции значений
		/// </summary>
		/// <param name="filterValue"></param>
		public void Remove(object filterValue) {
			if (filterValue == null)
				return;

			if (this.Values != null)
				this.Values.Remove(filterValue);
		}

		/// <summary>
		/// Метод очищения коллекции значений
		/// </summary>
		public void Clear() {
			if (this.Values != null)
				this.Values.Clear();
		}

		#endregion методы
	}
}